package com.oot2d.world;

import com.oot2d.entity.Entity;
import com.oot2d.entity.NPC;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.tiled.TiledMap;
import com.oot2d.util.WorldManager;

import java.util.ArrayList;

public class Map {
    private TiledMap map;
    public Tile[][][] tiles;
    public ArrayList<Entity> entities;
    public ArrayList<NPC> npcs;
    private int width, height;

    //Layer constants
    private static final int COLLISION = 0;
    private static final int INTERACT = 1;
    private static final int GROUND = 2;
    private static final int PROPS = 3;
    private static final int OVERLAY = 4;

    public Map(String s)
    {
        entities = new ArrayList<Entity>();
        npcs = new ArrayList<NPC>();

        try {
            map = new TiledMap("res/maps/" + s + ".tmx", "res/maps");
            width = map.getWidth();
            height = map.getHeight();
            tiles = new Tile[width][height][5];

        } catch (SlickException e) {
            System.err.println(e.getMessage());
        }
    }

    public void load()
    {
        if (map == null)
            return;

        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                for (int k = 0; k < 5; k++) {
                    int id = map.getTileId(i, j, k);

                    if (k == COLLISION)
                        tiles[i][j][k] = new Tile(i, j, Integer.parseInt(map.getTileProperty(id, "type", "-1")));
                    else
                        tiles[i][j][k] = new Tile(i, j);
                }
            }
        }

        int count = map.getObjectCount(0);
        for (int i = 0; i < count; i++) {
            String s = map.getObjectType(0, i);
            if (s.equals("entity")) {
                Entity e = WorldManager.loadEntity(Integer.parseInt(map.getObjectProperty(0, i, "id", "0")));
                e.setPos(map.getObjectX(0, i), map.getObjectY(0, i) - (e.getHeight() - 16.0f));
                e.setID(i);
                entities.add(e);
            } else if (s.equals("npc")) {
                NPC n = WorldManager.loadNPC(Integer.parseInt(map.getObjectProperty(0, i, "id", "0")));
                n.setPos(map.getObjectX(0, i), map.getObjectY(0, i) - (n.getHeight() - 16.0f));
                n.setID(i);
                npcs.add(n);
            }
        }
    }

    public int getWidth()
    {
        return width;
    }

    public int getHeight()
    {
        return height;
    }

    public Tile tileAt(float x, float y, int z)
    {
        int i = (int)((x - (x % 16.0f)) / 16.0f);
        int j = (int)((y - (y % 16.0f)) / 16.0f);

        return tiles[i][j][z];
    }

    public ArrayList<Entity> getEntities()
    {
        return entities;
    }

    public ArrayList<NPC> getNPCs()
    {
        return npcs;
    }

    public void update(int d)
    {
        //Update entities & npcs
        int size = entities.size();
        for (int i = 0; i < size; i++) {
            Entity e = entities.get(i);
            e.update(d);
        }

        size = npcs.size();
        for (int i = 0; i < size; i++) {
            NPC e = npcs.get(i);
            e.update(d);
        }
    }

    public void draw(Graphics q, float wx, float wy)
    {
        Tile g = tileAt(wx, wy, GROUND);
        map.render((int)g.getWX(), (int)g.getWY(), g.getX(), g.getY(), 31, 21, GROUND, false);
        map.render((int)g.getWX(), (int)g.getWY(), g.getX(), g.getY(), 31, 21, PROPS, false);

        //Render entities & npcs
        int size = entities.size();
        for (int i = 0; i < size; i++) {
            //Check if inside bounds
            Entity e = entities.get(i);
            if ((e.getX() >= (wx - e.getWidth()) && e.getX() <= (wx + 480.0f + e.getWidth())) &&
                    (e.getY() >= (wy - e.getHeight()) && e.getY() <= (wy + 320.0f + e.getHeight())))
                e.draw(q);
        }

        size = npcs.size();
        for (int i = 0; i < size; i++) {
            //Check if inside bounds
            NPC e = npcs.get(i);
            if ((e.getX() >= (wx - e.getWidth()) && e.getX() <= (wx + 480.0f + e.getWidth())) &&
                    (e.getY() >= (wy - e.getHeight()) && e.getY() <= (wy + 320.0f + e.getHeight())))
                e.draw(q);
        }
    }

    public void drawOverlay(float wx, float wy)
    {
        Tile o = tileAt(wx, wy, OVERLAY);
        map.render((int)o.getWX(), (int)o.getWY(), o.getX(), o.getY(), 31, 21, OVERLAY, false);
    }
}
